package mpp;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

class Ex2q1
{
	static int counter = 0;
	private static final Lock _lock = new Lock(){
		private volatile boolean[] flag = new boolean[2];
		private volatile int victim = -1;
		
		@Override
		public void lock() {
			int i = ThreadID.get();
			int j = 1-i;
			flag[i] = true; 
			 victim  = i; 
			 while (flag[j] && victim == i) {};		
		}

		@Override
		public void unlock() {
			int i = ThreadID.get();
			flag[i] = false;			
		}

		@Override
		public void lockInterruptibly() throws InterruptedException {
			// TODO Auto-generated method stub
			
		}

		@Override
		public Condition newCondition() {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public boolean tryLock() {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public boolean tryLock(long time, TimeUnit unit)
				throws InterruptedException {
			// TODO Auto-generated method stub
			return false;
		}};

	public static void main(String[] args)
	{
		int n;
		try
		{
			n = Integer.parseInt(args[0]);
		} catch (Exception e)
		{
			System.out.println("Wrong Input");
			return;
		}

		Thread[] threads = new Thread[n];

		//Initialize threads
		for (int i = 0; i < n; i++)
		{
			threads[i] = new Thread(){
				
				final int ITERATIONS = 100000;
				
				public void run()
				{
					for (int i = 0; i < ITERATIONS; i++)
					{
						_lock.lock();
						try
						{
							int temp = counter;
							temp++;
							counter = temp;
						} finally
						{
							_lock.unlock();
						}
					}
				}
			};
		}
		
		//start the threads
		for (int i = 0; i < n; i++)
		{
			threads[i].start();
		}

		//waiting for the threads to end
		try
		{
			for (int i = 0; i < n; i++)
			{
				threads[i].join();
			}
		} catch (InterruptedException e)
		{
		}

		System.out.format("The couner is: %d\n", counter);
	}
	
}



class Ex2q1nv
{
	static int counter = 0;
	private static final Lock _lock = new Lock(){
		private boolean[] flag = new boolean[2];
		private int victim = -1;
		
		@Override
		public void lock() {
			int i = ThreadID.get();
			int j = 1-i;
			flag[i] = true; 
			 victim  = i; 
			 while (flag[j] && victim == i) {};		
		}

		@Override
		public void unlock() {
			int i = ThreadID.get();
			flag[i] = false;			
		}

		@Override
		public void lockInterruptibly() throws InterruptedException {
			// TODO Auto-generated method stub
			
		}

		@Override
		public Condition newCondition() {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public boolean tryLock() {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public boolean tryLock(long time, TimeUnit unit)
				throws InterruptedException {
			// TODO Auto-generated method stub
			return false;
		}};

	public static void main(String[] args)
	{
		int n;
		try
		{
			n = Integer.parseInt(args[0]);
		} catch (Exception e)
		{
			System.out.println("Wrong Input");
			return;
		}

		Thread[] threads = new Thread[n];


		//Initialize threads
		for (int i = 0; i < n; i++)
		{
			threads[i] = new Thread(){
				
				final int ITERATIONS = 100000;
				
				public void run()
				{
					for (int i = 0; i < ITERATIONS; i++)
					{
						_lock.lock();
						try
						{
							int temp = counter;
							temp++;
							counter = temp;
						} finally
						{
							_lock.unlock();
						}
					}
				}
			};
		}
		
		//start the threads
		for (int i = 0; i < n; i++)
		{
			threads[i].start();
		}

		//waiting for the threads to end
		try
		{
			for (int i = 0; i < n; i++)
			{
				threads[i].join();
			}
		} catch (InterruptedException e)
		{
		}

		System.out.format("The couner is: %d\n", counter);
	}
	


}


class ThreadID {
	private static volatile int nextID = 0;
	private static class ThreadLocalID extends ThreadLocal<Integer> {
	
		protected synchronized Integer initialValue() {
			return nextID++;
			}
		}
	
	 private static ThreadLocalID threadID = new ThreadLocalID();
	 
	 public static int get() {
		 return threadID.get();
		 }
	 
	 public static void set(int index) {
		 threadID.set(index);
		 }
}